<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
		<meta name="viewport"
			content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0,user-scalable=no">
		<meta name="format-detection" content="telephone=no">
		<title>THREE.js Loader</title>
		<style>
			html,
			body {
				width: 100%;
				height: 100%;
				overflow: hidden;
				margin: 0;
				padding: 0;
				background-color: #000;
				font-family: Helvetica;
			}

			#stage,
			video,
			canvas {
				position: absolute;
				top: 0;
				left: 0;
				width: 100%;
				height: 100%;
			}

			canvas {
				z-index: 99;
			}
		</style>
	</head>
	<body>
		<div id="stage"></div>
		<script type="text/javascript" src="https://cdn.bootcss.com/eruda/1.2.6/eruda.min.js"></script>
		<script type="text/javascript" src="js/three.min.js"></script>
		<script type="text/javascript" src="js/loader/inflate.min.js"></script>
		<script type="text/javascript" src="js/OrbitControls.js"></script>
		<script type="text/javascript" src="js/loader/FBXLoader.js"></script>

		<script type="text/javascript">
			eruda.init();

			var u = navigator.userAgent;
			var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; // android终端
			var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); // ios终端
			var isWeiXin = !!u.match(/MicroMessenger/i); // 微信

			var stage = document.querySelector('#stage');
			var container;
			var scene, camera, renderer, controls;
			var SCREEN_WIDTH = window.innerWidth;
			var SCREEN_HEIGHT = window.innerHeight;
			var angle = 90;
			var nearest = 1;
			var farthest = 1000;
			var mixers = new Array();
			var clock = new THREE.Clock();

			let curve = null,
				model = null;
			let progress = 0; // 物体运动时在运动路径的初始位置，范围0~1
			// 影响运动速率的一个值，范围0~1，需要和渲染频率结合计算才能得到真正的速率
			const velocity = 0.005;

			init();
			initSourceWebcam();

			function init() {
				container = document.createElement('div');
				stage.appendChild(container);
				// 创建场景
				scene = new THREE.Scene();
				// 创建相机
				camera = new THREE.PerspectiveCamera(angle, SCREEN_WIDTH / SCREEN_HEIGHT, nearest, farthest);
				camera.position.set(200, 100, 0);
				// 环境光
				scene.add(new THREE.AmbientLight(4210752, 3));
				// 平行光
				var light = new THREE.DirectionalLight(16777215, 1);
				light.position.set(0, 50, 50);
				scene.add(light);
				// 坐标系
				var axes = new THREE.AxesHelper(30);
				scene.add(axes);

				makeCurve();

				// 加载提示
				var manager = new THREE.LoadingManager();
				manager.onProgress = function(item, loaded, total) {
					console.log(item, loaded, total);
				};

				var onProgress = function(xhr) {
					if (xhr.lengthComputable) {
						var percentComplete = xhr.loaded / xhr.total * 100;
						console.log(Math.round(percentComplete, 2) + '% downloaded');
					}
				};

				var onError = function(xhr) {
					console.error(xhr);
				};



				var fbx_loader = new THREE.FBXLoader(manager);

				// fbx静态模型
				/* fbx_loader.load('./models/miku/miku.fbx', function(object){
				     object.scale.multiplyScalar(.1);

				     scene.add(object);
				 }, onProgress, onError); */

				// fbx动画
				fbx_loader.load('./models/fbx/baiying.FBX', function(object) {

					object.mixer = new THREE.AnimationMixer(object);
					mixers.push(object.mixer);

					var action = object.mixer.clipAction(object.animations[0]);
					action.play();

					object.scale.multiplyScalar(.1);
					object.position.set(-3, 0, 0);

					scene.add(object);

					model = object;
				}, onProgress, onError);



				// 创建渲染器
				renderer = new THREE.WebGLRenderer({
					antialias: true, // 平滑效果
					alpha: true, // canvas背景透明
				});
				renderer.setPixelRatio(window.devicePixelRatio);
				renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
				container.appendChild(renderer.domElement);

				// 创建控制器
				controls = new THREE.OrbitControls(camera, renderer.domElement);
				controls.target.set(0, 0, 0);

				animate();

				window.addEventListener('resize', onWindowResize, false);
			}

			function makeCurve() {
				let cPosition = camera.position.clone();
				console.log(cPosition)
				//Create a closed wavey loop
				/* curve = new THREE.CatmullRomCurve3([
					new THREE.Vector3(0, 1, 0),
					new THREE.Vector3(5, 3, 0),
					new THREE.Vector3(10, 5, 0),
					cPosition
				]); */

				curve = new THREE.CatmullRomCurve3([
					cPosition,
					new THREE.Vector3(10, 5, 0),
					new THREE.Vector3(5, 3, 0),
					new THREE.Vector3(0, 1, 0),
				]);
				curve.curveType = "catmullrom";
				curve.closed = false; //设置是否闭环
				curve.tension = 0.5; //设置线的张力，0为无弧度折线

				// 为曲线添加材质在场景中显示出来，不显示也不会影响运动轨迹，相当于一个Helper
				const points = curve.getPoints(50);
				const geometry = new THREE.BufferGeometry().setFromPoints(points);
				const material = new THREE.LineBasicMaterial({
					color: 0x000000
				});

				// Create the final object to add to the scene
				const curveObject = new THREE.Line(geometry, material);
				scene.add(curveObject)
			}

			// 物体沿线移动方法
			function moveOnCurve() {
				if (curve == null || model == null) {
					console.log("Loading")
				} else {
					if (progress <= 1 - velocity) {
						const point = curve.getPointAt(progress); //获取样条曲线指定点坐标
						const pointBox = curve.getPointAt(progress + velocity); //获取样条曲线指定点坐标

						if (point && pointBox) {
							model.position.set(point.x, point.y, point.z);

							//因为这个模型加载进来默认面部是正对Z轴负方向的，所以直接lookAt会导致出现倒着跑的现象，这里用重新设置朝向的方法来解决。
							// model.lookAt(pointBox.x, pointBox.y, pointBox.z);

							var targetPos = pointBox //目标位置点
							var offsetAngle = 0 //目标移动时的朝向偏移

							// //以下代码在多段路径时可重复执行
							var mtx = new THREE.Matrix4() //创建一个4维矩阵
							// .lookAt ( eye : Vector3, target : Vector3, up : Vector3 ) : this,构造一个旋转矩阵，从eye 指向 target，由向量 up 定向。
							mtx.lookAt(model.position, targetPos, model.up) //设置朝向
							mtx.multiply(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, offsetAngle, 0)))
							var toRot = new THREE.Quaternion().setFromRotationMatrix(mtx) //计算出需要进行旋转的四元数值
							model.quaternion.slerp(toRot, 0.2)
						}

						progress += velocity;
					} else {
						progress = 0;
					}
				}

			};

			function animate() {
				requestAnimationFrame(animate);
				render();
			}

			function render() {
				var delta = clock.getDelta();
				moveOnCurve();
				if (mixers.length > 0) {
					for (var i = 0; i < mixers.length; i++) {
						mixers[i].update(delta);
					}
				}
				controls.update();
				renderer.render(scene, camera);
			}

			// 窗口改变重置摄像头
			function onWindowResize() {
				SCREEN_WIDTH = window.innerWidth;
				SCREEN_HEIGHT = window.innerHeight;
				renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
				camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
				camera.updateProjectionMatrix();
			}

			// 获取视频流
			function initSourceWebcam() {
				// check API is available
				if (navigator.mediaDevices === undefined || navigator.mediaDevices.enumerateDevices === undefined || navigator
					.mediaDevices.getUserMedia === undefined) {
					console.log('Not Support')
				} else {
					// get available devices
					navigator.mediaDevices.enumerateDevices().then(function(devices) {
						if (isiOS) {
							navigator.mediaDevices.getUserMedia({
								audio: false,
								video: {
									facingMode: 'environment'
								}
							}).then(successFunc).catch(errorFunc);
						} else {
							var videoSourceId;
							for (var i = 0; i < devices.length; i++) {
								var deviceInfo = devices[i];
								if (deviceInfo.kind == "videoinput" && deviceInfo.label.split(', ')[1] ==
									"facing back") {
									videoSourceId = deviceInfo.deviceId;
								}
							}
							navigator.mediaDevices.getUserMedia({
								audio: false,
								video: {
									optional: [{
										sourceId: videoSourceId
									}]
								}
							}).then(successFunc).catch(errorFunc);
						}
					}).catch(errorFunc);
				}
			}

			// 摄像头调起成功
			function successFunc(stream) {
				var domElement = document.createElement('video');
				domElement.setAttribute('autoplay', '');
				domElement.setAttribute('muted', '');
				domElement.setAttribute('playsinline', '');
				domElement.style.width = document.documentElement.clientWidth + 'px';
				domElement.style.height = document.documentElement.clientHeight + 'px';

				domElement.srcObject = stream;
				document.body.addEventListener('click', function() {
					domElement.play();
				});

				// wait until the video stream is ready
				var interval = setInterval(function() {
					if (!domElement.videoWidth) {
						return;
					}

					clearInterval(interval);
					stage.appendChild(domElement);
				}, 1000 / 50);
			}

			// 摄像头调起失败
			function errorFunc(err) {
				console.log(err);
			}
		</script>
	</body>
</html>
